import { BadRequestException } from '@nestjs/common';
import {
  FindOptionsRelations,
  ObjectLiteral,
  Repository,
  SelectQueryBuilder,
} from 'typeorm';

import { ShowDto } from '../dto/show.dto';

function handleIds(ids: ShowDto['ids'] | string) {
  let idList: string[] = [];

  if (!ids) return idList;

  if (typeof ids === 'string') {
    idList = ids.includes(',') ? ids.split(',') : [ids];
  } else {
    idList = ids;
  }

  idList = idList.filter((v) => v);

  return idList;
}

export function showBuilder<T extends ObjectLiteral>(
  repository: Repository<T>,
  dto: ShowDto,
  relation?: FindOptionsRelations<T> | string[],
): SelectQueryBuilder<T> | undefined {
  const queryBuilder = repository.createQueryBuilder();

  const name = repository.metadata.name;

  if (Array.isArray(relation)) {
    relation.forEach((item) => {
      queryBuilder.leftJoinAndSelect(`${name}.${item}`, item);
    });
  }

  if (dto.id) {
    return queryBuilder.where(`${name}.id = :id`, { id: dto.id });
  } else if (dto.ids) {
    const idList = handleIds(dto.ids);

    if (!idList.length) return;

    return queryBuilder.where(`${name}.id IN (:...ids)`, { ids: idList });
  }

  return;
}

export function showBuilderEntity<T extends ObjectLiteral, D>(
  repository: Repository<T>,
  dto: D,
  relation?: FindOptionsRelations<T> | string[],
): Promise<'ids' extends keyof D ? T[] : T | null>;
export async function showBuilderEntity<
  T extends ObjectLiteral,
  D extends ShowDto,
>(
  repository: Repository<T>,
  dto: D,
  relation?: FindOptionsRelations<T> | string[],
) {
  const queryBuilder = showBuilder(repository, dto, relation);

  if (!queryBuilder) {
    if (dto.ids) return [];
    return;
  }

  if (dto.id) {
    return queryBuilder.getOne();
  } else if (dto.ids) {
    return queryBuilder.getMany();
  }

  throw new BadRequestException('id or ids is required');
}
